package com.example.wxsmart.config;

import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjectUtil;
import com.example.wxsmart.WxSmartApplication;
import com.example.wxsmart.exception.ServiceException;
import com.example.wxsmart.util.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;

/**
 * @author Luojunxian
 * @data 2022/6/1 9:12
 * @classname ExceptionConfig
 */
@RestControllerAdvice
public class ExceptionConfig {
    private static final Logger log = LoggerFactory.getLogger(ExceptionConfig.class);

    /**
     * 根路径
     */
    public static final String ROOT_PATH = WxSmartApplication.class.getPackage().getName();

    /**
     * 全局异常处理
     *
     * @param request 请求
     * @param e       e
     * @return {@code Result<String>}
     */
    @ExceptionHandler
    public Result<String> doException(HttpServletRequest request, Exception e){
        //记录日志,通知运维,通知开发
        log.error(getFirstStackTraceByPackageName(e, ROOT_PATH));
        return Result.fail("服务器出错:" + e.getMessage());
    }

    /**
     * 处理所有接口数据校验异常
     *
     * @param e e
     * @return {@code Result<String>}
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result<String> handleMethodArgumentNotValidException(MethodArgumentNotValidException e){
        return Result.fail(e.getBindingResult().getAllErrors().get(0).getDefaultMessage(), getFirstStackTraceByPackageName(e, ROOT_PATH));
    }

    @ExceptionHandler({ServiceException.class})
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<String> handleError(ServiceException e) {
        log.error(getFirstStackTraceByPackageName(e, ROOT_PATH));
        return Result.fail("服务器出错:" + e.getMessage());
    }

    /**
     * 获取第一条包含参数包名的堆栈记录
     *
     * @param throwable   异常类
     * @param packageName 指定包名
     * @return 某行堆栈信息
     * @author fengshuonan
     * @date 2020/12/16 16:04
     */
    public static String getFirstStackTraceByPackageName(Throwable throwable, String packageName) {

        if (ObjectUtil.hasEmpty(throwable)) {
            return "";
        }

        // 获取所有堆栈信息
        StackTraceElement[] stackTraceElements = throwable.getStackTrace();

        // 默认返回第一条堆栈信息
        String stackTraceElementString = stackTraceElements[0].toString();

        // 包名没传就返第一条堆栈信息
        if (CharSequenceUtil.isEmpty(packageName)) {
            return stackTraceElementString;
        }

        // 找到项目包名开头的第一条异常信息
        for (StackTraceElement stackTraceElement : stackTraceElements) {
            if (stackTraceElement.toString().contains(packageName)) {
                stackTraceElementString = stackTraceElement.toString();
                break;
            }
        }

        return stackTraceElementString;
    }
}
